package com.jfinal.weixin.sdk.encrypt;

import com.alibaba.fastjson.JSONObject;
import com.jfinal.weixin.sdk.utils.Base64Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * Created by yuzhou on 17/1/4.
 */
public class WXBizDataCrypt {

  private static Logger _log = LoggerFactory.getLogger(WXBizDataCrypt.class);

  public String getErrMsg() {
    return errMsg;
  }

  private String errMsg = null;

  private String appId = null;
  private String sessionKey = null;

  public WXBizDataCrypt(String appId, String sessionKey) {
    this.appId = appId;
    this.sessionKey = sessionKey;
  }

  public JSONObject decryptData(String encryptedData, String iv) {

    try {
      byte[] _sessionKey = Base64Utils.decodeBase64(this.sessionKey);
      byte[] _encryptedData = Base64Utils.decodeBase64(encryptedData);
      byte[] _iv = Base64Utils.decodeBase64(iv);

      Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

      SecretKeySpec secretKeySpec = new SecretKeySpec(_sessionKey, "AES");
      IvParameterSpec ivParameterSpec = new IvParameterSpec(_iv);
      cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);

      byte[] original = cipher.doFinal(_encryptedData);
      byte[] bytes = PKCS7Encoder.decode(original);

      String originalString = new String(bytes, "UTF-8");

      JSONObject jsonObject = JSONObject.parseObject(originalString);

      JSONObject watermark = jsonObject.getJSONObject("watermark");
      if(watermark == null) {
        this.errMsg = "watermark不存在";
        return null;
      }

      String _appId = watermark.getString("appid");

      if(_appId == null) {
        this.errMsg = "appid不存在";
        return null;
      }

      if(!_appId.equals(appId)) {
        this.errMsg = "appid不一致";
        return null;
      }

      return jsonObject;

    } catch (Exception e) {
      _log.error("Fail to decrypt data", e);
      this.errMsg = "解析数据失败";
    }

    return null;
  }

}
